#ifndef __TPS_IMPL_H__
#define __TPS_IMPL_H__

#include "tps_typeof.h"
#include "tps_function.h"
#include "tps_utils.h"
#include "tps_mtd_class_impl.h"

#include <memory>
#include <iterator>
#include <algorithm>

#define TPS_BEGIN_MAP_IMPL(iface_) \
	namespace iface_##PS \
	{ \
		namespace PSImpl \
		{ \
			typedef iface_ IFacePSType; \
			template <unsigned id> \
			struct ProxyRegItem \
			{ \
				typedef Tps::Private::NullType Type; \
			}; \
			template <unsigned id> \
			struct StubRegItem \
			{ \
				typedef Tps::Private::NullType Type; \
			}; \
			typedef Tps::Private::TypeItem<50> TypeItemN; \
			char (& GetPSItemIndex(void *))[1];

#define TPS_METHOD_IMPL(mtd_) \
    typedef TPS_TYPEOF(&IFacePSType::mtd_) mtd_##MtdType; \
    typedef Tps::Private::Method<mtd_##MtdType> mtd_##MtdData; \
    TPS_CREATE_MTD_INDEX(mtd_) \
    TPS_MTD_PROXY_CLASS_IMPL(mtd_) \
    typedef mtd_##ProxyMtdWrap<Tps::Private::NullType, mtd_##MtdData, mtd_##MtdData::ParamsCount, !!mtd_##MtdData::IsConstMtd> mtd_##ProxyWrapType; \
    TPS_REG_PROXY_CLASS(mtd_##ProxyWrapType, mtd_##ID) \
    TPS_MTD_STUB_CLASS_IMPL(mtd_) \
    typedef mtd_##StubMtdWrap<mtd_##MtdData> mtd_##StubWrapType; \
    TPS_REG_STUB_CLASS(mtd_##StubWrapType, mtd_##ID)

#define TPS_END_MAP_IMPL() \
        TPS_CREATE_MTD_INDEX(EndMtdIndex) \
        typedef Tps::Private::CreateMtdTypeList<ProxyRegItem, 1, EndMtdIndexID>::List ProxyList; \
        typedef Tps::Private::CreateMtdTypeList<StubRegItem, 1, EndMtdIndexID>::List StubList; \
    } \
     \
    template <typename RemoteMethod> \
    class Proxy \
        : public Tps::Private::InheritFromProxyList<Proxy<RemoteMethod>, PSImpl::ProxyList> \
    { \
    public: \
        typedef RemoteMethod RemoteMethodType; \
        typedef typename RemoteMethodType::Serializer Serializer; \
        typedef typename RemoteMethodType::Deserializer Deserializer; \
        typedef typename RemoteMethodType::InstIdType InstIdType; \
        typedef typename RemoteMethodType::ClsIdType ClsIdType; \
        typedef typename RemoteMethodType::MtdIdType MtdIdType; \
    \
        Proxy(RemoteMethod *remoteMtd, InstIdType instId, ClsIdType clsId) \
            : RemoteMtd(remoteMtd) \
            , InstId(instId) \
            , ClsId(clsId) \
        { \
        } \
        \
        std::auto_ptr<Serializer> CreateSerializer(InstIdType const &instId, ClsIdType const &clsId, \
            MtdIdType const &mtdId, unsigned paramsCount, bool isConst) \
        { \
            return RemoteMtd->CreateSerializer(instId, clsId, mtdId, paramsCount, isConst); \
        } \
        std::auto_ptr<Serializer> CreateDeserializer(void const *buffer, unsigned long bufferLen) \
        { \
            return RemoteMtd->CreateDeserializer(buffer, bufferLen); \
        } \
        std::auto_ptr<Deserializer> CallRemoteMethod(std::auto_ptr<Serializer> pack) \
        { \
            return RemoteMtd->CallRemoteMethod(pack); \
        } \
        InstIdType GetInstanceId() const \
        { \
            return InstId; \
        } \
        ClsIdType GetClsId() const \
        { \
            return ClsId; \
        } \
        \
    private: \
        RemoteMethod *RemoteMtd; \
        InstIdType InstId; \
        ClsIdType ClsId; \
    }; \
    \
    template <typename RemoteMethod> \
    class Stub \
        : private Tps::Private::NonCopyable \
    { \
    public: \
        typedef PSImpl::IFacePSType IFaceType; \
        \
        typedef RemoteMethod RemoteMethodType; \
        typedef typename RemoteMethodType::Serializer Serializer; \
        typedef typename RemoteMethodType::InstIdType InstIdType; \
        typedef typename RemoteMethodType::ClsIdType ClsIdType; \
        typedef typename RemoteMethodType::MtdIdType MtdIdType; \
        \
        Stub(IFaceType *object, RemoteMethodType *remoteMtd) \
            : Object(object) \
            , RemoteMtd(remoteMtd) \
        { \
        } \
        \
        std::auto_ptr<typename RemoteMethodType::BufferType> CallMethod(void const *buffer, unsigned long bufferLen) \
        { \
            std::auto_ptr<typename RemoteMethodType::Deserializer> Unpacker = \
                RemoteMtd->CreateDeserializer(buffer, bufferLen); \
            MtdIdType MtdId = Unpacker->GetMtdId(); \
            std::auto_ptr<typename RemoteMethodType::Serializer> Packer = RemoteMtd->CreateSerializer( \
                Unpacker->GetInstId(), Unpacker->GetClsId(), MtdId, Unpacker->GetParamsCount(), Unpacker->IsConst()); \
            Tps::Private::CallStubMethod<Stubs>(Object, MtdId, Unpacker.get(), Packer.get()); \
            Unpacker->Pack(Packer.get()); \
            typedef typename RemoteMethodType::BufferType BufferType; \
            std::auto_ptr<BufferType> RetBuffer(new BufferType); \
            std::copy( \
                    &reinterpret_cast<typename BufferType::value_type const *>(Packer->GetBuffer())[0], \
                    &reinterpret_cast<typename BufferType::value_type const *>(Packer->GetBuffer())[Packer->GetBufferLen()], \
                    std::back_inserter(*RetBuffer.get()) \
                ); \
            return RetBuffer; \
        } \
        \
    private: \
        IFaceType *Object; \
        RemoteMethodType *RemoteMtd; \
        typedef PSImpl::StubList Stubs; \
    }; \
}

#endif	// !__TPS_IMPL_H__



/*
 
*/
